package com.mmd.base.auth;

import cn.hutool.core.util.IdUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.alibaba.fastjson.JSONObject;
import com.mmd.base.pojo.entity.UserInfo;
import com.mmd.base.utils.EncryptionUtils;
import com.mmd.core.constant.KeyConstant;
import com.mmd.core.enums.LoginEnum;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import java.util.Set;
import java.util.concurrent.TimeUnit;

@Slf4j
public class TokenTemplate {
    private static final StringRedisTemplate redisTemplate = SpringUtil.getApplicationContext().getBean(StringRedisTemplate.class);

    // 默认存储30天
    public static final long timeout = 60 * 60 * 24 * 30 * 1000L;

    // 密钥
    private static final String secret = "S6SB!R8uyBSlM0!cV4@&SYq#fMa*9lOMe4tB&3phi2anJX@Rie0jg#w^O!ue7kFwLf*OP@5!Kh6&gyttoB4ix&*^YQDGQyegOc%";

    // 发行人
    private static final String issuer = "mmd";

    // 密钥
    private static final byte[] key = secret.getBytes();

    /**
     * 创建并且保存jwt信息
     * @param loginEnum 登录类型
     * @param subject 用户信息
     * @param <T> 用户其他信息类型
     * @return key
     */
    public static <T> String saveToken(LoginEnum loginEnum, UserInfo<T> subject)
    {
        return saveToken(loginEnum,subject,0);
    }

    /**
     * 创建并且保存jwt信息
     * @param loginEnum 登录类型
     * @param subject 用户信息
     * @param timeout 超时时间
     * @param <T> 用户其他信息类型
     * @return key
     */
    public static <T> String saveToken(LoginEnum loginEnum, UserInfo<T> subject, long timeout)
    {
        return saveToken(loginEnum,subject,timeout,null);
    }

    /**
     * 创建并且保存jwt信息
     * @param loginEnum 登录类型
     * @param subject 用户信息
     * @param timeout 超时时间
     * @param timeUnit 时间枚举
     * @param <T> 用户其他信息类型
     * @return key
     */
    @SneakyThrows
    public static <T> String saveToken(LoginEnum loginEnum, UserInfo<T> subject, long timeout, TimeUnit timeUnit)
    {
        Set<String> keys = redisTemplate.keys(getPrefix(loginEnum)+"=>" +EncryptionUtils.encryptionMD5(subject.getUsername())+IdUtil.fastSimpleUUID() + "*");
        if(keys != null) redisTemplate.delete(keys);
        String token = createToken(loginEnum,subject);
        redisTemplate.opsForValue().set(token,createValue(subject), timeout < 1 ? TokenTemplate.timeout : timeout ,timeUnit == null || timeout < 1 ? TimeUnit.MILLISECONDS : timeUnit);
        return token;
    }

    /**
     * 创建value
     * @param subject value内容
     * @param <T> 类型
     */
    public static <T> String createValue(UserInfo<T> subject)
    {
        return JSONObject.toJSONString(subject);
    }

    /**
     * 创建token
     * @param loginEnum 登录类型
     * @param subject 用户信息
     * @param <T> 类型
     */
    @SneakyThrows
    public static <T> String createToken(LoginEnum loginEnum, UserInfo<T> subject){
        return getPrefix(loginEnum)+"=>" +EncryptionUtils.encryptionMD5(subject.getUsername())+IdUtil.fastSimpleUUID() ;
    }

    /**
     * 获取用户信息
     * @param value String
     * @param tClass 映射类型
     */
    public static <T> UserInfo<T> getSubject(String value,Class<T> tClass)
    {
        return (UserInfo<T>)JSONObject.parseObject(value,UserInfo.class);
    }

    /**
     * 获取前缀
     * @param loginEnum 登录类型
     */
    public static String getPrefix(LoginEnum loginEnum)
    {
        return KeyConstant.REDIS_AUTHENTICATION_PREFIX + loginEnum.getValue();
    }

    /**
     * 删除信息
     */
    public static void clear(String key)
    {
        redisTemplate.delete(key);
    }
}
